﻿using System;
using System.Threading;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Windows;
using System.Windows.Forms;

namespace PedesTrainProject.Core
{
    public class Simulation : ICoreTraffic, ICoreGUIRun
    {
        private int speed=1;

        public int Speed
        {
            get { return speed; }
            set { speed = value; }
        }
        private DateTime start_time;
        private DateTime end_time;
        public static DateTime current_time;
        private Grid.Grid grid;
        private PictureBox pb;
        private SimulationCreator sc;
        private GUI.SimulationCreator scGUI;
        private Bitmap drawArea;
        private Data.Statistics statistic;

        public void setSpeed(int _speed)
        {
            speed = _speed;
        }

       
        public Bitmap DrawArea
        {
            get { return drawArea; }
            set { drawArea = value; }
        }
        public SimulationCreator Sc
        {
            get { return sc; }
            set { sc = value; }
        }
        public PictureBox Pb
        {
            get { return pb; }
            set { pb = value; }
        }
        

        private Traffic.CarFlow carFlow;
        private Traffic.PedestrianFlow pedestrianFlow;
        private Visualization visualization;

        private bool running;

        public bool Running
        {
            get { return running; }
            set { running = value; }
        }
        private Thread simulationThread;
        private Thread timerThread;
        private List<Thread> lightsThread = new List<Thread>();
        private List<Thread> pedestrianLightsThread = new List<Thread>();
        
        private bool[] gridJam;
        private int[] gridJamCount;
        private const int SIZE_GRID = 16;
        private const bool JAMMED = false;
        private const bool NOT_JAMMED = true;

       // public Simulation(Grid.Grid _grid, Traffic.CarFlow _carFlow, Traffic.PedestrianFlow _pedestrianFlow, DateTime _start_time, DateTime _end_time, int _speed)
//        {

  //      }
        public void incrementTime()
        {
            while (true)
            {
                current_time = current_time.AddSeconds(1.0);
                scGUI.updateTime(current_time);
                Thread.Sleep(1000/speed);
                //System.Console.WriteLine(current_time.ToLongTimeString());
            }
        }

        public Simulation(SimulationCreator _sc, Graphics e, PictureBox _pb, Bitmap _drawArea, GUI.SimulationCreator _scGUI, DateTime _start_time, DateTime _end_time)
        {
            //grid = _grid;

            start_time = _start_time;
            end_time = _end_time;

            current_time = start_time;
            scGUI = _scGUI;
            pb = _pb;
            lightsThread.Capacity = 100;
            sc = _sc;
            drawArea = _drawArea;
            visualization = new Visualization(this, e, _scGUI);
//            lightsThread.Add(null);
            
            List<KeyValuePair<Grid.InFlowFlag, KeyValuePair<int, int>>> inFlowFlags = new List<KeyValuePair<Grid.InFlowFlag, KeyValuePair<int, int>>>();

            statistic = new Data.Statistics();
            gridJam = new bool[SIZE_GRID];
            gridJamCount = new int[SIZE_GRID];
            for (int i = 0; i < SIZE_GRID; i++)
            {
                gridJam[i] = NOT_JAMMED;
                gridJamCount[i] = 0;
            }

            int j = 0;
            foreach (Grid.Tile tile in sc.TempGrid.Tiles)
            {
                if (tile.Road.Name == "straight")
                {
                    int i = 0;
                    foreach (Grid.Lane lane in tile.Road.Lanes)
                    {
                        if (lane.InFlow != null)
                        {
                            KeyValuePair<int, int> kvp = new KeyValuePair<int, int>(j, i);
                            inFlowFlags.Add(new KeyValuePair<Grid.InFlowFlag, KeyValuePair<int, int>>(lane.InFlow, kvp));
                            //Console.WriteLine("dodalem flage " + i + " w tajlu " + j);
                        }
                        i++;
                    }
                }
                j++;
            }
           
            
            carFlow = new Traffic.CarFlow(inFlowFlags, this);
            pedestrianFlow = new Traffic.PedestrianFlow(this);
            timerThread = new Thread(incrementTime);
            run();
            running = true;
           
            
        }

        public DateTime getCurrentTime()
        {
            lock (this)
            {
                return current_time;
            }
        }

        public void adjustSpeed(int speed)
        {
        }

        public int getSpeed()
        {
            return speed;
        }

        public void run()
        {
            int index=0;
            statistic = new Data.Statistics();
            statistic.StartTime = DateTime.Now;
            statistic.JamTotal = 0;
            statistic.CarTotal = 0;

            foreach (Grid.Tile tile in sc.TempGrid.Tiles)
            {   
                if (tile.Road.Name=="crossing")
                {
                        for (int i = 0; i < 4; i++)
                        {
                            int ind = index;
                            //System.Console.WriteLine("chuj");
                            Grid.CarLight cl = tile.Road.getCarLight(i);
                            //tile.Road.getCarLight(i).change(this, index);
                            lightsThread.Add(new Thread(kurwa => cl.change(this,ind)));
                        }
                }
                index++;
                
            }
            index = 0;
            foreach (Grid.Tile tile in sc.TempGrid.Tiles)
            {
                if (tile.Road.Skin != "none")
                {
                    foreach(Grid.PedestrianLight pl in tile.Road.PedestrianLights)
                    {
                        int ind = index;
                       // System.Console.WriteLine("chujeczek");
                        Grid.PedestrianLight pl1 = pl;
                        //tile.Road.getCarLight(i).change(this, index);
                        lightsThread.Add(new Thread(kurwamac => pl1.change(this, ind)));
                    }
                }
                index++;

            }
            foreach (Thread t in lightsThread)
            {
                t.Start();
            }
            carFlow.run();
            timerThread.Start();
            //pedestrianFlow.run();
        }

        public void pause()
        {
            carFlow.pause();
            pedestrianFlow.pause();
            visualization.pause();
        }

        public void resume()
        {
            carFlow.pause();
            pedestrianFlow.pause();
            visualization.pause();
        }

        public void stop()
        {
            carFlow.stop();
            pedestrianFlow.stop();
            visualization.stop();
            statistic.CarTotal = carFlow.getTotalCar();
            foreach (Thread t in lightsThread)
            {
                t.Abort();
            }
            timerThread.Abort();
            running = false;
            statistic.EndTime = DateTime.Now;
        }

        public void animateCar(Vector position)
        {
            visualization.animateCar(position);
        }

        public void animatePedestrian(Vector position)
        {
            //visualization.animatePedestrian(position);
        }

        public void drawAll()
        {
            visualization.drawAll();
        }

        public Grid.Grid getGrid()
        {
            return sc.TempGrid;
        }

        public void changeLights( int x, int y, Color color, Grid.Directions direction)
        {
            visualization.changeLights(x, y, color, direction);
        }
        public void changePedestrianLights(int x, int y, Color color, Grid.Directions direction)
        {
            visualization.changeLights(x, y, color, direction);
        }

        public void switchLanesDirection(int tile)
        {
            sc.TempGrid.Tiles[tile].Road.Lanes[8].switchDirection();
            sc.TempGrid.Tiles[tile].Road.Lanes[9].switchDirection();
        }

        public Data.Statistics getStatistic()
        {
            return statistic;
        }

        public void addJam(int gridPosition)
        {
            lock (gridJam)
            {
                if (gridJam[gridPosition] == NOT_JAMMED)
                {
                    if(gridJamCount[gridPosition] == 0)
                        statistic.JamTotal++;
                    
                    gridJam[gridPosition] = JAMMED;
                    gridJamCount[gridPosition]++;
                }
            }
        }

        public void releaseJam(int gridPosition)
        {
            lock (gridJam)
            {
                gridJam[gridPosition] = NOT_JAMMED;
                if (gridJamCount[gridPosition] > 0)
                    gridJamCount[gridPosition]--;
            }
        }
    }
}
